package pl.edu.pb.wi.pwnography.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import pl.edu.pb.wi.pwnography.model.form.ClusteringForm;
import pl.edu.pb.wi.pwnography.modules.KMeansClustering;
import pl.edu.pb.wi.pwnography.session.FileList;

@Controller
@RequestMapping("/module/kmeans")
public class KMeansModule {
    private static final Logger log = Logger
	    .getLogger(KNearestNeighborModule.class.getName());

    private static final String CLUSTERING_DESCRIPTION = "Grupowanie algorytmem k-średnich dla k = %d oraz metodą inicjalizacji %s";
    private static final String CLUSTERING_SUCCESS = "Grupowanie dla k = %d metodą inicjalizacji %s zakończyło się sukcesem.";
    private static final String CLUSTERING_ERROR = "W trakcie grupowania wystąpił błąd.";

    private FileList fileList;

    @Autowired
    public KMeansModule(FileList fileList) {
	this.fileList = fileList;
    }

    @ModelAttribute("floatColumnList")
    public List<String> getFloatColumnNames() {
	return fileList.getActiveFile().getFloatTypeColumnNames();
    }

    @ModelAttribute("initTypes")
    public List<KMeansClustering.STARTING_POINTS_INIT> getMetricList() {
	return Arrays.asList(KMeansClustering.STARTING_POINTS_INIT.values());
    }

    @RequestMapping(value = "clustering", method = RequestMethod.GET)
    public String clustering(Model model) {
	log.info("Clustering GET.");

	model.addAttribute("form", new ClusteringForm());

	return "module/kmeans/clustering";
    }

    @RequestMapping(value = "clustering", method = RequestMethod.POST)
    public String clustering(
	    @ModelAttribute("form") @Valid ClusteringForm form,
	    BindingResult results, Model model) {
	log.info("Clustering POST.");

	if (form.getKmeans() > fileList.getActiveFile().getRowCount()) {
	    results.addError(new FieldError("form", "kmeans",
		    "Nie może być więcej średnich niż obiektów."));
	}

	if (results.hasErrors()) {
	    return "module/kmeans/clustering";
	}

	try {
	    Map<String, List<Object>> data = KMeansClustering.cluster(
		    fileList.getActiveFile(), form.getExcludedColumns(),
		    form.getKmeans(), form.getResultColumnName(),
		    form.getInitType());

	    String description = String.format(CLUSTERING_DESCRIPTION,
		    form.getKmeans(), form.getInitType().toString());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(CLUSTERING_SUCCESS,
			    form.getKmeans(), form.getInitType().toString()) }));
	} catch (Exception e) {
	    log.info(String.format(
		    "Problem with K-Means clustering. Exception: %s",
		    e.getMessage()));

	    model.addAttribute(
		    "errorMsgs",
		    Arrays.asList(new String[] { CLUSTERING_ERROR,
			    e.getMessage() }));
	}

	return "module/kmeans/clustering";
    }
}
